package com.quanyou.base.framework.dao.impl;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import tk.mybatis.mapper.entity.Example;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.quanyou.base.framework.dao.AbstractDao;
import com.quanyou.base.framework.dao.domain.BaseDomain;
import com.quanyou.base.framework.dao.model.BaseModel;
import com.quanyou.base.framework.dao.model.PageParams;
import com.quanyou.base.framework.dao.model.PageResults;
import com.quanyou.base.framework.dao.mybatis.BasicMapper;

/**
 * 基础服务类
 * Created by forever on 6/19/15.
 */
@SuppressWarnings("unchecked")
public abstract class AbstractDaoImpl<E extends BaseDomain<PK>, PK extends Serializable, M extends BaseModel<E>> implements
        AbstractDao<E, PK, M> {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    protected BasicMapper<E, PK> baseMapper;

    private final Long MAX_PAGE_SIZE = 100L;

    //@Autowired

    private Class<E> entityClass;
    private Class<PK> pkClass;
    private Class<M> modelClass;

    @SuppressWarnings("unchecked")
    public AbstractDaoImpl() {

        //返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的直接超类的 Type。
        Type genType = getClass().getGenericSuperclass();
        while(!(genType.equals("java.lang.Object"))) {
            if (genType instanceof ParameterizedType) {
                //返回表示此类型实际类型参数的 Type 对象的数组。
                Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
                if (params.length > 2) {
                    if (params[0] instanceof Class) {
                        entityClass = (Class<E>) params[0];
                    }
                    pkClass = (Class<PK>)params[1];

                    //特殊处理BaseModel
                    if(params[2] instanceof Class) {
                        modelClass = (Class<M>)params[2];
                    } else if(params[2] instanceof ParameterizedType) {
                        modelClass = (Class<M>)((ParameterizedType)params[2]).getRawType();
                    }
                    break;
                }
            } else {
                genType = ((Class)genType).getGenericSuperclass();
            }
        }
    }

    @Override
    public E get(PK pk) {
        return baseMapper.getByPrimaryKey(pk);
    }

    @Override
    public E get(E e) {
        return baseMapper.selectOne(e);
    }

    @Override
    public E getByExample(Example example) {
        List<E> list = baseMapper.selectByExample(example);
        if(list != null && list.size()>0) {
            return list.get(0);
        } else {
            return null;
        }
    }

    @Override
    public PK save(E e) {
        baseMapper.insertSelective(e);
        return e.getId();
    }

    @Override
    public int save(Collection<E> entityList) {
        if (entityList == null || entityList.size() == 0) {
            return 0;
        } else {
        	int count = 0;
        	for (E e : entityList) {
        		count += baseMapper.insertSelective(e);
			}
        	return count;
//            return (int)entityList.parallelStream()
//                    .map(baseMapper::insertSelective)
//                    .filter(i -> i>0).count();
        }
    }

    @Override
    public int updateByPrimaryKey(E e) {
        return baseMapper.updateByPrimaryKey(e);
    }

    @Override
    public int updateSelectiveByPrimaryKey(E e) {
        return baseMapper.updateSelectiveByPrimaryKey(e);
    }

    @Override
    public PageResults<E> queryPageResults(PageParams <E> pp) {
        //RowBounds rb = new RowBounds();
        Long pageNum = pp.getPageIndex();
        Long pageSize = pp.getPageSize();
        //前置处理

        if(pageSize > MAX_PAGE_SIZE){
            pageSize = MAX_PAGE_SIZE;
        }

        List<E> results = new ArrayList<>(0);

        PageHelper.startPage(pageNum.intValue(), pageSize.intValue());
        E pm = pp.getParamModel();
        if(entityClass != null) {
            Example example = new Example(entityClass);
            Example.Criteria criteria = example.createCriteria();
            PropertyDescriptor[] propArray =  BeanUtils.getPropertyDescriptors(entityClass);
            for(PropertyDescriptor pd : propArray) {
                if(pd.getPropertyType().equals(Class.class)) {
                    continue;
                }
                if (pm == null) {
                    continue;
                }
                try {
                    Object value = pd.getReadMethod().invoke(pm);
                    if(value != null) {
                        criteria.andEqualTo(pd.getName(), value);
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
            if(StringUtils.isNotEmpty(pp.getOrderBy())) {
                example.setOrderByClause(pp.getOrderBy() + (pp.isAsc() ? " ASC" : " DESC"));
            }
            results = baseMapper.selectByExample(example);
        } else {
            results = baseMapper.select(pp.getPm());
        }
        //List<E> results = baseMapper.selectByRowBounds(pp.getPm(),rb);
        PageResults<E> pr = new PageResults<>();
        Page page = (Page)results;
        long total = page.getTotal();
        pr.setTotalCount(total);
        pr.setResults(results);
        pr.setParams(pp);
        return pr;
    }

    @Override
    public PageResults<E> queryPageResults(PageParams<E> pp, Example example) {
        logger.debug("开始进行分页查询...");

        Long pageNum = pp.getPageIndex();
        Long pageSize = pp.getPageSize();
        //前置处理

        logger.debug("分页条件：{pageSize:{}, pageNum:{}}", pageSize, pageNum);

        if(pageSize > MAX_PAGE_SIZE){
            logger.warn("页大小超过100行，强制设定为100！");
            pageSize = MAX_PAGE_SIZE;
        }

        PageHelper.startPage(pageNum.intValue(), pageSize.intValue());
        List<E> results = baseMapper.selectByExample(example);
        logger.debug("查询数据库完成，返回记录数：{}", results == null ? 0 : results.size());
        //List<E> results = baseMapper.selectByRowBounds(pp.getPm(),rb);
        PageResults<E> pr = new PageResults<>();
        Page page = (Page)results;
        long total = page.getTotal();
        pr.setTotalCount(total);
        pr.setResults(results);
        pr.setParams(pp);
        logger.debug("分页查询结束。");
        return pr;
    }

    @Override
    public List<E> findByPropertys(E e) {
        return baseMapper.select(e);
    }

    @Override
    public void delete(PK id) {
        baseMapper.deleteByPrimaryKey(id);
    }

    @Override
    public void delete(List<E> objectlist) {
        if (objectlist == null) {
            return;
        }
        //TODO 批量删除的效率不见的比较高
//        objectlist.forEach(baseMapper::delete);
        for (E e : objectlist) {
        	baseMapper.delete(e);
		}
    }

    @Override
    public boolean exists(E e) {
        int count = baseMapper.selectCount(e);
        return count > 0;
    }

    @Override
    public List<E> findByExample(Example example) {
        return baseMapper.selectByExample(example);
    }

    @Override
    public int selectCount(E e) {
        return baseMapper.selectCount(e);
    }

    @Override
    public int selectCountByExample(Example example) {
        return baseMapper.selectCountByExample(example);
    }

    @Override
    public int updateByExampleSelective(E record, Example example) {
        return baseMapper.updateByExampleSelective(record, example);
    }

    @Override
    public List<E> listAll() {
        try {
            return baseMapper.select(entityClass.newInstance());
        } catch (InstantiationException | IllegalAccessException e) {
            logger.error("查询全部记录失败！", e);
            return new ArrayList<>(0);
        }
    }

    @Override
    public int update(E object) {
        return baseMapper.updateSelectiveByPrimaryKey(object);
    }

    @Override
    public int updateByExample(E record, Example example) {
        return baseMapper.updateByExample(record, example);
    }
}